package ru.urfc.portal.services;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;

import javax.xml.rpc.ServiceException;

import org.apache.axis.encoding.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import services.DMSDocumentExternalInfo;
import services.DMSDocumentsExternalServiceLocator;
import services.DMSDocumentsExternalServicePortType;
import services.MD5Hash;
import services.SOAPException;

public class DmsManager {

	private static DMSDocumentsExternalServicePortType port;
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	public static String DEFAULT_CATEGORY_UUID = "pstcimfs000080000ig6mn7nqo3i5kio";
	public static String DEFAULT_FOLDER_UUID = "corebofs000080000ig6mp3l4vfn8v2g";
	public static String USER_UUID = "corebolg800fg0000ig7kbr1gr7bjkq8"; // "employfs000080000ig7kb6bdnpkvf5o";  
	public static String HOST = "172.16.0.62:9080"; // "ssh-gate.naumen.ru:10225";  

	public String dms; // docUuid
	public String lc;
	public String incomingNumber; // dmsRegistrationNumber
	public Date incomingDate; // dmsRegistrationDate

	public DMSDocumentsExternalServicePortType getPort() {
		if (port == null) {
			try {
				DMSDocumentsExternalServiceLocator service = new DMSDocumentsExternalServiceLocator();
				service.setDMSDocumentsExternalServiceHttpPortEndpointAddress("http://"
						+ HOST + "/fx/xfire/DMSDocumentsExternalService");
				port = service.getDMSDocumentsExternalServiceHttpPort();
			} catch (ServiceException ex) {
				logger.error(ex.getMessage());
				ex.printStackTrace();
			}
		}
		return port;
	}

	/**
	 * fills dms, lc
	 */

	// public String SendString(String text) {
	// String fileUUID = null;
	// InputStream stream;
	// try {
	// stream = new ByteArrayInputStream(text.getBytes("UTF-8"));
	// fileUUID = SendStream(stream);
	// stream.close();
	// } catch (Exception e) {
	// logger.error(e.getMessage());
	// e.printStackTrace();
	// }
	// return fileUUID;
	// }
	//
	// public String SendFile(String filename) {
	// String fileUUID = null;
	// FileInputStream stream;
	// try {
	// stream = new FileInputStream(filename);
	// fileUUID = SendStream(stream);
	// stream.close();
	// } catch (Exception e) {
	// logger.error(e.getMessage());
	// e.printStackTrace();
	// }
	// return fileUUID;
	// }
	//
	// public String SendStream(InputStream stream) {
	// logger.info("Opening file to transfer...");
	// try {
	// String fileId = getPort().initFileTransfer();
	// byte[] buf = new byte[1000];
	// int len = 1000;
	// logger.info("Sending file...");
	// while (true) {
	// int read = stream.read(buf, 0, len);
	// if (read < 0) {
	// break;
	// }
	// String data = Base64.encode(buf, 0, read);
	// Arrays.fill(buf, (byte) 0);
	// String packetHash = getHashByString(data);
	// getPort().sendFilePacket(fileId, data, packetHash);
	// }
	// return fileId;
	//
	// } catch (Exception e) {
	// logger.error(e.getMessage());
	// e.printStackTrace();
	// return null;
	// }
	// }

	public static int CHUNK_SIZE = 1000;

	public void sendChunk(String fileId, byte[] bytes, int off, int len)
			throws SOAPException, RemoteException {
		logger.info("Sending file...");

		String data = Base64.encode(bytes, off, len);
		getPort().sendFilePacket(fileId, data, getHash(data.getBytes()));
	}

	public String sendArray(byte[] bytes) throws SOAPException, RemoteException {

		logger.info("Opening file to transfer...");
		String fileId = getPort().initFileTransfer();

		int residue = bytes.length % CHUNK_SIZE;
		int chunks = bytes.length / CHUNK_SIZE;
		int off = 0;
		for (; off < chunks * CHUNK_SIZE; off += CHUNK_SIZE) {
			sendChunk(fileId, bytes, off, CHUNK_SIZE);
		}
		if (residue > 0) {
			sendChunk(fileId, bytes, off, residue);
		}
		return fileId;

	}

	// public String getHashByFilename(String filename) {
	// try {
	// return MD5Hash.hashToHashString(MD5Hash.calculateHashOfFile(filename));
	// } catch (Exception e) {
	// logger.error(e.getMessage());
	// e.printStackTrace();
	// return null;
	// }
	// }
	//
	// public String getHashByString(String data) {
	// return getHash(data.getBytes());
	// }
	public String getHash(byte[] bytes) {
		try {
			return MD5Hash.hashToHashString(MD5Hash.calculateHash(bytes));
		} catch (NoSuchAlgorithmException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return null;
		}
	}

	public void addContent(String filename, boolean isPrimary)
			throws IOException {
		File file = new File(filename);
		String description = file.getName();
		byte[] bytes;
		FileInputStream fin;
		fin = new FileInputStream(file);
		bytes = new byte[(int) file.length()];
		fin.read(bytes);
		fin.close();
		String fileId = sendArray(bytes);
		String totalHash = getHash(bytes);
		if (isPrimary) {
			getPort().addContentFileToDocument(dms, fileId, file.getName(),
					null, description, totalHash, false);
		} else {
			getPort().addAdditionalFileToDocument(dms, fileId, file.getName(),
					null, description, totalHash, false);
		}
	}

	public boolean tryAddDoc(String title, String regnum, Calendar dateOut,
			String html, String primaryFilename, String secondaryFilenames[],
			String folder, String category) {

		DMSDocumentExternalInfo info = new DMSDocumentExternalInfo();
		info.setTitle(title);
		info.setRegistrationNumber(regnum);
		info.setDateOut(dateOut);
		info.setCategoryUUID(category);
		info.setParentUUID(folder);
		try {
			logger.info("Adding document...");
			dms = addDoc(info, html);
			if (primaryFilename != null) {
				addContent(primaryFilename, true);
			}
			for (String filename : secondaryFilenames) {
				addContent(filename, false);
			}
			return tryGetDocumentLC();
			// TODO see html, filenames
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	private String addDoc(DMSDocumentExternalInfo info, String html)
			throws RemoteException, SOAPException {
		if (html == null) {
			return getPort().addDocument(info, USER_UUID, null, null);
		} else {
			byte[] bytes = html.getBytes();
			String fileId = sendArray(bytes);
			return getPort().addDocument(info, USER_UUID, fileId,
					getHash(bytes));
		}
	}

	public boolean tryGetDocumentLC(String dms) {
		this.dms = dms;
		return tryGetDocumentLC();
	}

	public boolean tryGetDocumentLC() {
		this.dms = dms;
		logger.info("Getting document lifecycle...");
		DMSDocumentExternalInfo info = null;
		try {
			info = getPort().getDocument(dms);
			lc = info.getDmsLifecycleState();
			incomingNumber = info.getDmsRegistrationNumber();
			incomingDate = info.getDmsRegistrationDate().getTime();
		} catch (Exception e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return false;
		}
		return true;
	}

}
